'use strict';

const pkgDir = require('pkg-dir').sync;
const path = require('path')
const npminstall = require('npminstall')
const pathExists = require('path-exists').sync;
const fse = require('fs-extra')
const { isObject } = require("@gsh-cli/utils")
const formatPath = require("@gsh-cli/format-path")
const { getLastestVersion, getDefaultRegistry } = require("@gsh-cli/npm-get-info")

class Package {
  constructor(options) {
    // options判空处理 
    if(!options) {
      throw new Error('Package的options传参不能为空')
    }
    if(!isObject(options)) {
      throw new Error('Package的options参数必须为对象')
    }
    // 用户指定的目标包所在目录
    this.targetPath = options.targetPath
    // 目标包的真实存储目录 
    this.storeDir = options.storeDir
    this.packageName = options.packageName
    this.packageVersion = options.packageVersion
    // package的缓存目录前缀
    this.cacheFilePathPrefix = this.packageName.replace('/', '_')
  }    

  async prepare() {
    // 有缓存目录但没有真实存在node_modules文件夹则需要创建它
    if(this.storeDir && !pathExists(this.storeDir)) {
      // mkdirpSync是确保目录存在，如果是mkdirSync则是在当前目录下创建，不能跨级
      fse.mkdirpSync(this.storeDir)
    }
    if(this.packageVersion === 'lastest') {
      this.packageVersion = await getLastestVersion(this.packageName)
    }
  }
  get cacheFilePath() {
    return path.resolve(this.storeDir, path.resolve(this.storeDir, `_${this.cacheFilePathPrefix}@${this.packageVersion}@${this.packageName}`))
  }

  getLastestCacheFilePath(lastestVersion) {
    return path.resolve(this.storeDir, path.resolve(this.storeDir, `_${this.cacheFilePathPrefix}@${lastestVersion}@${this.packageName}`))
  }

  // 检测当前包是否存在
  async exists() {
    // 需要了解npm install的缓存机制：https://www.ruanyifeng.com/blog/2016/01/npm-install.html
    // 找到/Users/gongshunhua/.gsh-cli/dependencies/node_modules，然后看到包名是_@gsh-cli_utils@1.0.15@@gsh-cli/
    // 如果包有缓存路径（代表没有传targetPath参数）
    await this.prepare()
    return pathExists(this.cacheFilePath)
  }

  // 根据targetPath获取包的入口文件（package.json中的main）
  async getRootFile() {
    async function _getRootFile(p) {
      // 1.获取packag.json所在目录
      const dir = await pkgDir(p)
      // 2.获取package.json的目录
      const packageDir = path.resolve(dir, 'package.json')
      if(dir && packageDir) {
        // 3.寻找main
        if(require(packageDir) && require(packageDir).main) {
          // 4.兼容系统路径
          return formatPath(path.resolve(dir, require(packageDir).main))
        }
      }
    }
    // 没有传指定的targetPath，则存在缓存路径，从缓存路径中的包获取入口文件路径
    if(this.storeDir) {
      return await _getRootFile(this.cacheFilePath)
    } else {
      // 如果指定，则从指定目录里面获取入口文件路径
      return await _getRootFile(this.targetPath)
    }
  }

  // 安装包
  async install() {
    console.log(this.targetPath)
    console.log('pp', this.storeDir)
    const _this = this
    // 获取最新version
    await this.prepare()
    await npminstall({
      root: this.targetPath,
      storeDir: this.storeDir,
      registry: getDefaultRegistry(true),
      pkgs: [{
        name: _this.packageName,
        version: _this.packageVersion
      }]
    })
  }

  // 更新包
  async update() {
    // 1.确保storeDir以及node_modules并对其进行最新版本的检测
    await this.prepare()
    // 2.对最新的版本进行检测
    const lastestVersion = await getLastestVersion(this.packageName)
    // 3.如果缓存中存在最新版本包则返回目录，否则则下载最新包至缓存
    if(pathExists(this.getLastestCacheFilePath(lastestVersion))) {
      return this.getLastestCacheFilePath(lastestVersion)
    } else {
      await npminstall({
        root: this.targetPath,
        storeDir: this.storeDir,
        registry: getDefaultRegistry(true),
        pkgs: [{
          name: this.packageName,
          version: lastestVersion
        }]
      })
    }
    this.packageVersion = lastestVersion
  }
}

module.exports = Package;

